package appml

import (
	"io"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"gitee.com/kitfast/resml"
)

func (m *AppManager) uploadsTick() {
	for range m.uploadTicker.C {
		m.uploads()
	}
}

func (m *AppManager) uploads() {
	for _, task := range m.config.Uploads {
		m.uploadTask(task)
	}
}

func (m *AppManager) uploadTask(task *ConfigUpload) {
	stat, err := os.Stat(task.Local)
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		log.Printf("upload error: %s", err)
		return
	}
	if !stat.IsDir() {
		m.uploadFile(task.Local, task.Remote, task.Append)
		return
	}
	err = filepath.Walk(task.Local, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return NewErr(runtime.Caller(0)).Err(err)
		}
		if info.IsDir() {
			return nil
		}
		rpath := filepath.ToSlash(strings.Trim(strings.TrimPrefix(path, task.Local), `/\`))
		m.uploadFile(path, task.Remote+"/"+rpath, task.Append)
		return nil
	})
	if err != nil {
		log.Printf("upload error: %s", err)
		return
	}
}

func (m *AppManager) uploadFile(path, uri string, append bool) {
	//log.Printf("uploading file: %s %s %t", path, uri, append)
	u, err := url.Parse(uri)
	if err != nil {
		log.Printf("upload error (parse remote url): %v", NewErr(runtime.Caller(0)).Err(err))
		return
	}
	meta, err := resml.MetaOfFile(path, m.etager)
	if err != nil {
		log.Printf("upload error (get file meta): %v", NewErr(runtime.Caller(0)).Err(err))
		return
	}
	fd, err := os.Open(path)
	if err != nil {
		log.Printf("upload error (open): %v", NewErr(runtime.Caller(0)).Err(err))
		return
	}
	defer fd.Close()
	res := m.uploadLogClient.Get(u)
	var up, us, fs int64
	if stat, err := fd.Stat(); err == nil {
		fs = stat.Size()
		us = fs
	}
	if append {
		if ar, ok := res.(resml.ResourceAppendable); ok {
			ar.Append()
		}
		rmeta, err := res.Meta()
		if err == nil && rmeta != nil {
			if cl := rmeta.ContentLength(); cl > 0 {
				if sp, err := fd.Seek(cl, io.SeekStart); err != nil {
					log.Printf("upload error (seek): %v", NewErr(runtime.Caller(0)).Err(err))
					return
				} else if sp < us {
					up = sp
					us -= sp
				} else {
					return // 远程长度大于等于定位位置，无需上传
				}
			}
		} else {
			log.Printf("get remote meta: %v", NewErr(runtime.Caller(0)).If(err))
		}
	}
	if err = res.Put(meta, fd); err != nil {
		log.Printf("upload error (put): %v", NewErr(runtime.Caller(0)).Err(err))
	} else {
		log.Printf("uploaded: [@%d](%d/%d) %s", up, us, fs, path)
	}
}
